﻿using CommonBehaviors.Actions;
using Styx;
using Styx.Common;
using Styx.TreeSharp;
using Styx.WoWInternals.WoWObjects;
using Styx.WoWInternals;
using Styx.CommonBot.Profiles.Quest.Order;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Media;
using System.Diagnostics;

#region [Method] - Class Redundancy
using HkM = SinisterD.Core.Managers.Hotkey_Manager;
using SB = SinisterD.Core.Helpers.Spell_Book;
using TM = SinisterD.Core.Managers.Talent_Manager;
using U = SinisterD.Core.Unit;
using S = SinisterD.Core.Spell;
using L = SinisterD.Core.Utilities.Log;
using CH = SinisterD.Core.Helpers.Condition_Helper;
#endregion  

namespace SinisterD.Rotation
{

    class Rotation
    {
        private static LocalPlayer Me { get { return StyxWoW.Me; } }
        private static WoWUnit currentTarget { get { return StyxWoW.Me.CurrentTarget; } }


        #region [Method] - Precombat Buffing
        public static async Task<bool> preCombatBuffing()
        {
            //var watch = Stopwatch.StartNew();
            if (HkM.manualOn || Me.Combat || !Me.IsAlive || (Me.Mounted || Me.OnTaxi))
                return true;
            //Pre-Combat Ambush
            if (await S.Cast(SB.spellAmbush, 5, HkM.ambushOn)) return true;
            //Poisons
            if (await S.Buff(SB.spellLeechingPoison,!U.auraExists(Me, SB.auraLeechingPoison) && TM.HaveTalent(TM.RogueTalents.LeechingPoison))) return true;
            if (await S.Buff(SB.spellCripplingPoison, !U.auraExists(Me, SB.auraCripplingPoison) && !TM.HaveTalent(TM.RogueTalents.LeechingPoison))) return true;
            if (await S.Buff(SB.spellDeadlyPoison, !U.auraExists(Me, SB.auraInstantPoison) && !U.auraExists(Me, SB.auraDeadlyPoison))) return true;            
            //if (await S.Buff(SB.spellBladeFlurry, !U.auraExists(Me, SB.auraBladeFlurry) && HkM.aoeOn)) return true;
            //watch.Stop();
            //var elapsedMs = watch.ElapsedMilliseconds;
            //L.combatLog("Elapsed Pre-Combat" + elapsedMs);
            return false;
        }
        #endregion

        #region [Method] - Combat Buffing
        
        public static async Task<bool> combatBuffing()
        {
            //var watch = Stopwatch.StartNew();
            if (HkM.manualOn || !Me.IsAlive || (Me.Mounted || Me.OnTaxi))
                return true;
            if (!Me.IsAutoAttacking && Me.GotTarget && currentTarget.IsAlive) { Lua.DoString("StartAttack()"); return true; }
            //Poisons
            if (await S.Buff(SB.spellLeechingPoison, !U.auraExists(Me, SB.auraLeechingPoison) && TM.HaveTalent(TM.RogueTalents.LeechingPoison))) return true;
            if (await S.Buff(SB.spellCripplingPoison, !U.auraExists(Me, SB.auraCripplingPoison) && !TM.HaveTalent(TM.RogueTalents.LeechingPoison))) return true;
            //Feint
            if (await S.Buff(SB.spellFeint, U.auraTimeLeft(Me, SB.auraFeint) < 500 && HkM.FeintOn)) return true;
            //Potion n Healthstone - usage
            if (Me.HealthPercent < 30 && HkM.ambushOn && ((TM.HaveTalent(TM.RogueTalents.CheatDeath) && U.auraExists(Me, SB.auraCheatingDeath)) || !TM.HaveTalent(TM.RogueTalents.CheatDeath) ))
            {
                await S.UseItem(SB.itemHealthstone, true);
                WoWItem Healthstone = Me.BagItems.FirstOrDefault(h => h.Entry == SB.itemHealthstone);
                await S.UseItem(SB.itemPotion, Healthstone == null);
            };
            //if (await S.Buff(SB.spellBladeFlurry, !U.auraExists(Me, SB.auraBladeFlurry) && HkM.aoeOn))return true;
            //watch.Stop();
            //var elapsedMs = watch.ElapsedMilliseconds;
            //if (elapsedMs > 0) { L.combatLog("Elapsed Combat" + elapsedMs); };
            return false;
        }
        #endregion

        #region [Method] - Combat Rotation

        public static async Task<bool> combatRotation()
        {

            if (HkM.manualOn || !Me.IsAlive || (!Me.GotTarget || !currentTarget.IsAlive) || (Me.Mounted || Me.OnTaxi))
                return true;
            ////Self-Healing actions
            //if (await S.Cast(SB.spellShiv, 5, (Me.CurrentTarget.HasAura("Enrage") ||HkM.healOn && U.auraExists(Me, SB.auraLeechingPoison) && Me.HealthPercent <= 92))) return true;
            if (await S.Buff(SB.auraRecuperate, !U.auraExists(Me, SB.auraRecuperate) && HkM.healOn && ((Me.HealthPercent <= 70 && U.CP >= 4) || !U.auraExists(Me, SB.auraRecuperate) && Me.HealthPercent <= 40 && U.CP > 1)))
                return true;
            ////Ranged actions
            //if (await S.Cast(SB.spellShurikenToss, 30, currentTarget.DistanceSqr > 35) && TM.HaveTalent(TM.RogueTalents.ShurikenToss)) return true;
            //if (await S.Cast(SB.spellDeadlyThrow, 30, currentTarget.DistanceSqr > 35) && TM.HaveTalent(TM.RogueTalents.DeadlyThrow) && U.CP == 5) return true;
            //if (await S.CastStatic(SB.spellThrow, 30, currentTarget.DistanceSqr > 26)) return true;
            //Main actions
            if (await S.Cast(SB.spellAmbush, 5, true))
                return true;
            //if (await S.Buff(SB.spellPreperation, !U.auraExists(Me, SB.auraVanish) && S.cooldownTimeLeft(SB.spellVanish) >= 30000) && HkM.vanishPrepOn && HkM.cooldownsOn) return true;
            //await S.GCD(SB.spellVanish, (currentTarget.DistanceSqr - (currentTarget.CombatReach * currentTarget.CombatReach) - 1 <= 25) && U.Energy < 90 && !U.auraExists(Me, SB.auraVanish) && !S.onCooldown(SB.spellVanish) && HkM.vanishPrepOn && HkM.cooldownsOn && (U.CP < 4 || (TM.HaveTalent(TM.RogueTalents.Anticipation) && U.auraStacks(Me, SB.auraAnticipation) < 4) && (TM.HaveTalent(TM.RogueTalents.ShadowFocus) && !U.auraExists(Me, SB.auraAdrenalineRush) && U.Energy >= 15 || TM.HaveTalent(TM.RogueTalents.Subterfuge) && U.Energy > 90 || !TM.HaveTalent(TM.RogueTalents.Subterfuge) && !(TM.HaveTalent(TM.RogueTalents.ShadowFocus) && U.Energy >= 60))));
            //if (await S.Cast(SB.spellBloodFury, 5, true)) return true;
            //if (await S.Cast(SB.spellBerserking, 5, true)) return true;
            //
            //if (await S.Cast(SB.spellArcaneTorrent, 5, U.Energy < 60)) return true;
            if (await S.Buff(SB.spellSliceAndDice, !U.auraExists(Me, SB.auraVanish) && (U.SnD < 2000 || (U.CP == 5 && U.SnD < 12000 && !U.auraExists(Me, SB.auraDeepInsight)))))
                return true;
            await S.GCD(SB.spellAdrenalineRush, (currentTarget.DistanceSqr - (currentTarget.CombatReach * currentTarget.CombatReach) - 1 <= 25) && (Me.CurrentEnergy <= 35 || U.BLup) && (S.cooldownTimeLeft(SB.spellKillingSpree) > 15000 || !HkM.KSon) && HkM.cooldownsOn && !(S.onCooldown(SB.auraAdrenalineRush)));
            if (await S.Cast(SB.spellKillingSpree, 10, (Me.CurrentEnergy <= 40 || U.BLup) && !U.auraExists(Me, SB.auraAdrenalineRush) && HkM.cooldownsOn && HkM.KSon))
                return true;

            //Use MfD only if target has less than 1mil HP, otherwise manually use it
            if (await S.Cast(SB.spellMarkedDorDeath, 30, (TM.HaveTalent(TM.RogueTalents.MarkedForDeath) && currentTarget.CurrentHealth < 1000000) && (U.CP <= 1 && U.auraExists(currentTarget, SB.auraRevealingStrike, true))))
                return true;

            //CP generators  
            if (!U.auraExists(Me, SB.auraVanish) && (U.CP < 5 || !U.auraExists(currentTarget, SB.auraRevealingStrike, true) || TM.HaveTalent(TM.RogueTalents.Anticipation) && U.AntiStacks <= 3 && !U.auraExists(Me, SB.auraDeepInsight)))
            {
                if (await S.Cast(SB.spellRevealingStrike, 5, U.Energy >= 17 && !U.auraExists(currentTarget, SB.auraRevealingStrike, true) /*|| U.auraTimeLeft(Me, SB.auraRevealingStrike, true) < 720*/))
                    return true;
                if (await S.Cast(SB.spellSinisterStrike, 5, U.Energy >= 17 && U.auraExists(currentTarget, SB.auraRevealingStrike, true)))
                    return true;
            }

            //CP finishers
            if (U.CP == 5 && U.auraExists(currentTarget, SB.auraRevealingStrike, true) && !U.auraExists(Me, SB.auraVanish) && (U.auraExists(Me, SB.auraDeepInsight) || !TM.HaveTalent(TM.RogueTalents.Anticipation) || TM.HaveTalent(TM.RogueTalents.Anticipation) && U.AntiStacks >= 4))
            {
                if (await S.Cast(SB.spellDeathFromAbove, 15, TM.HaveTalent(TM.RogueTalents.DeathFromAbove)))
                    return true;
                if (await S.Cast(SB.spellEviscerate, 5, !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && !HkM.aoeOn || !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && HkM.aoeOn && U.auraExists(currentTarget, SB.auraCrimsonTempest, true)))
                    return true;
                if (await S.Cast(SB.spellCrimsonTempest, 5, CH.FinisherEnable() && !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && HkM.aoeOn && !U.auraExists(currentTarget, SB.auraCrimsonTempest, true)))
                    return true;
            };
            //watch.Stop();
            //var elapsedMs = watch.ElapsedMilliseconds;
            //if (elapsedMs >= 2) { L.combatLog("Elapsed Combat" + elapsedMs); };
            return false;
        }
        public static async Task<bool> combatRotation2()
        {
            if (HkM.manualOn || !Me.IsAlive || (!Me.GotTarget || !currentTarget.IsAlive) || (Me.Mounted || Me.OnTaxi))
                return true;
            
            switch (Me.Specialization)
            {
                case (WoWSpec.RogueSubtlety):
                {
                    if (await S.Cast(SB.spellAmbush, 5, true)) return true;
                    if (await S.Cast(SB.spellBackstab, 5, (Me.ComboPoints < 5 && Me.CurrentTarget.MeIsBehind && U.Energy >= 80) && !Me.HasAura(115192) && !Me.HasAura("Shadow Dance") && (!Me.HasAura("Vanish") || !Me.HasAura("Stealth")))) return true;
                    if (await S.Cast(SB.spellHemo, 5, Me.ComboPoints < 5 && !Me.CurrentTarget.MeIsBehind)) return true;


                    //rupture,cycle_targets=1,if=(!ticking|remains<duration*0.3|(buff.shadow_reflection.remains>8&dot.rupture.remains<12))&target.time_to_die>=8
                    if (await S.Cast(SB.spellRupture, 5, Me.ComboPoints == 5 && (Core.Spell.GetAuraTimeLeft(1943, Me.CurrentTarget) < 8 || !currentTarget.HasAura("Rupture")))) return true; //Rupture
                    if (await S.Cast(SB.spellSliceAndDice, 20, Me.ComboPoints == 5 && (Core.Spell.GetAuraTimeLeft(5171, Me) < 10 || !Me.HasAura(SB.auraSliceAndDice)))) return true;
                    if (await S.Cast(SB.spellEviscerate, 5, Me.ComboPoints == 5 && (Core.Spell.GetAuraTimeLeft(5171, Me) > 10 && Core.Spell.GetAuraTimeLeft(1943, Me.CurrentTarget) > 8))) return true;

                    break;
                }
                #region Combat SPec
                case (WoWSpec.RogueCombat):
                {

                    if (await S.Buff(SB.auraRecuperate, !U.auraExists(Me, SB.auraRecuperate) && HkM.healOn && ((Me.HealthPercent <= 70 && U.CP >= 4) || !U.auraExists(Me, SB.auraRecuperate) && Me.HealthPercent <= 40 && U.CP > 1)))
                        return true;

                    if (await S.Cast(SB.spellAmbush, 5, true))
                        return true;

                    if (await S.Buff(SB.spellSliceAndDice, !U.auraExists(Me, SB.auraVanish) && (U.SnD < 2000 || (U.CP == 5 && U.SnD < 12000 && !U.auraExists(Me, SB.auraDeepInsight)))))
                        return true;
                    await S.GCD(SB.spellAdrenalineRush, (currentTarget.DistanceSqr - (currentTarget.CombatReach * currentTarget.CombatReach) - 1 <= 25) && (Me.CurrentEnergy <= 35 || U.BLup) && (S.cooldownTimeLeft(SB.spellKillingSpree) > 15000 || !HkM.KSon) && HkM.cooldownsOn && !(S.onCooldown(SB.auraAdrenalineRush)));
                    if (await S.Cast(SB.spellKillingSpree, 10, (Me.CurrentEnergy <= 40 || U.BLup) && !U.auraExists(Me, SB.auraAdrenalineRush) && HkM.cooldownsOn && HkM.KSon))
                        return true;

                    if (await S.Cast(SB.spellMarkedDorDeath, 30, (TM.HaveTalent(TM.RogueTalents.MarkedForDeath) && currentTarget.CurrentHealth < 1000000) && (U.CP <= 1 && U.auraExists(currentTarget, SB.auraRevealingStrike, true))))
                        return true;

                    //CP generators  
                    if (!U.auraExists(Me, SB.auraVanish) && (U.CP < 5 || !U.auraExists(currentTarget, SB.auraRevealingStrike, true) || TM.HaveTalent(TM.RogueTalents.Anticipation) && U.AntiStacks <= 3 && !U.auraExists(Me, SB.auraDeepInsight)))
                    {
                        if (await S.Cast(SB.spellRevealingStrike, 5, U.Energy >= 17 && !U.auraExists(currentTarget, SB.auraRevealingStrike, true) /*|| U.auraTimeLeft(Me, SB.auraRevealingStrike, true) < 720*/))
                            return true;
                        if (await S.Cast(SB.spellSinisterStrike, 5, U.Energy >= 17 && U.auraExists(currentTarget, SB.auraRevealingStrike, true)))
                            return true;
                    }

                    //CP finishers
                    if (U.CP == 5 && U.auraExists(currentTarget, SB.auraRevealingStrike, true) && !U.auraExists(Me, SB.auraVanish) && (U.auraExists(Me, SB.auraDeepInsight) || !TM.HaveTalent(TM.RogueTalents.Anticipation) || TM.HaveTalent(TM.RogueTalents.Anticipation) && U.AntiStacks >= 4))
                    {
                        if (await S.Cast(SB.spellDeathFromAbove, 15, TM.HaveTalent(TM.RogueTalents.DeathFromAbove)))
                            return true;
                        if (await S.Cast(SB.spellEviscerate, 5, !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && !HkM.aoeOn || !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && HkM.aoeOn && U.auraExists(currentTarget, SB.auraCrimsonTempest, true)))
                            return true;
                        if (await S.Cast(SB.spellCrimsonTempest, 5, CH.FinisherEnable() && !TM.HaveTalent(TM.RogueTalents.DeathFromAbove) && HkM.aoeOn && !U.auraExists(currentTarget, SB.auraCrimsonTempest, true)))
                            return true;
                    };
                    break;
                } 
                #endregion
            }


            
            return false;
        }
        
        #endregion
    }
    
}
